package com.ziiwee.reduce.rest.condition;

import com.ziiwee.reduce.rest.condition.impls.*;

import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;

public class Conditions {

    public static Condition and(Collection<Condition> values) {
        return new LogicConditionImpl(LogicOperation.AND, new ArrayList<>(values));
    }

    public static Condition and(Condition... values) {
        List<Condition> list = new ArrayList<>();
        for (Condition value : values) {
            if(value!=null){
                list.add(value);
            }
        }
        return new LogicConditionImpl(LogicOperation.AND, list);
    }

    public static Condition or(Collection<Condition> values) {
        return new LogicConditionImpl(LogicOperation.OR, new ArrayList<>(values));
    }

    public static Condition or(Condition... values) {
        List<Condition> list = new ArrayList<>();
        for (Condition value : values) {
            if(value!=null){
                list.add(value);
            }
        }
        return new LogicConditionImpl(LogicOperation.OR, list);
    }

    public static Condition like(String field, String value) {
        return new GeneralConditionImpl(field, GeneralOperation.LIKE, Collections.singletonList(value));
    }

//    public static <T> Condition in(String field, T... values) {
//        return new GeneralConditionImpl(field, GeneralOperation.IN, Arrays.asList(values));
//    }

    public static <T> Condition in(String field, List<T> values) {
        return new GeneralConditionImpl(field, GeneralOperation.IN, new ArrayList<>(values));
    }

//    public static <T> Condition notIn(String field, T... values) {
//        return new GeneralConditionImpl(field, GeneralOperation.NOT_IN, Arrays.asList(values));
//    }
    public static <T> Condition notIn(String field, List<T> values) {
        return new GeneralConditionImpl(field, GeneralOperation.NOT_IN, new ArrayList<>(values));
    }

    public static Condition isNull(String field) {
        return new GeneralConditionImpl(field, GeneralOperation.IS_NULL, null);
    }

    public static Condition isNotNull(String field) {
        return new GeneralConditionImpl(field, GeneralOperation.IS_NOT_NULL, null);
    }

    public static Condition eq(String field, Object value) {
        return new GeneralConditionImpl(field, GeneralOperation.EQUAL, Collections.singletonList(value));
    }

    public static Condition ne(String field, Object value) {
        return new GeneralConditionImpl(field, GeneralOperation.NOT_EQUAL, Collections.singletonList(value));
    }


    public static <T extends Comparable<T>> Condition gt(String field, T value) {
        return new GeneralConditionImpl(field, GeneralOperation.GREATER_THAN, Collections.singletonList(value));
    }


    public static <T extends Comparable<T>> Condition gte(String field, T value) {
        return new GeneralConditionImpl(field, GeneralOperation.GREATER_THAN_OR_EQUAL_TO, Collections.singletonList(value));
    }

    public static <T extends Comparable<T>> Condition lt(String field, T value) {
        return new GeneralConditionImpl(field, GeneralOperation.LESS_THAN, Collections.singletonList(value));
    }

    public static <T extends Comparable<T>> Condition lte(String field, T value) {
        return new GeneralConditionImpl(field, GeneralOperation.LESS_THAN_OR_EQUAL_TO, Collections.singletonList(value));
    }

    public static <T extends Comparable<T>> Condition between(String field, T value1, T value2) {
        return new GeneralConditionImpl(field, GeneralOperation.BETWEEN, Arrays.asList(value1, value2));
    }

    public static void forEachGeneralCondition(Condition condition, Consumer<GeneralCondition> consumer) {
        if (condition instanceof GeneralCondition) {
            consumer.accept((GeneralCondition) condition);
        } else {
            ((LogicCondition) condition).getValues().forEach(it -> forEachGeneralCondition(it, consumer));
        }
    }

    public static Condition mapGeneralCondition(Condition condition, Function<GeneralCondition, GeneralCondition> mapping) {
        if (condition instanceof GeneralCondition) {
            condition = mapping.apply((GeneralCondition) condition);
        } else {
            Iterator<Condition> iterator = ((LogicCondition) condition).getValues().iterator();
            while (iterator.hasNext()) {
                Condition next = iterator.next();
                next = mapGeneralCondition(next, mapping);
                if (next == null) {
                    iterator.remove();
                }
            }
        }
        return condition;
    }
}
